package edu.study.common.util;

import com.ctrip.framework.apollo.ConfigService;
import edu.study.api.common.enums.BaseResultCodeEnum;
import edu.study.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.springframework.util.Assert;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * @author yanjiawei
 */
@Slf4j
public class DateUtils {
    public static final String SHORT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String SHORT_DATE_FORMAT2 = "yyyy/MM/dd";
    public static final String SHORT_DATE_GBK_FORMAT = "yyyy年MM月dd日";
    public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm";
    public static final String DATE_GBK_FORMAT = "yyyy年MM月dd日 HH时mm分";
    public static final String LONG_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String LONG_DATE_GBK_FORMAT = "yyyy年MM月dd日 HH时mm分ss秒";
    public static final String MAIL_DATE_FORMAT = "yyyyMMddHHmmss";
    public static final String MAIL_DATE_HHMM_FORMAT = "HH:mm";
    public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss:SSS";
    public static final String FULL_DATE_GBK_FORMAT = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒";
    // ============================1.Date2String=====================================
    public static final String FULL_DATE_COMPACT_FORMAT = "yyyyMMddHHmmssSSS";
    public static final String LDAP_DATE_FORMAT = "yyyyMMddHHmm'Z'";
    public static final String US_LOCALE_DATE_FORMAT = "EEE MMM dd HH:mm:ss zzz yyyy";
    public static final String MAIL_DATE_YEAR_PART_FORMAT = "yyMMdd";
    public static final String MAIL_DATE_DT_PART_FORMAT = "yyyyMMdd";
    public static final String MAIL_DATE_HOUR_DT_PART_FORMAT = "yyyyMMddHH";
    public static final String MAIL_DATE_MINUTE_DT_PART_FORMAT = "yyyyMMddHHmm";
    public static final String MAIL_TIME_TM_PART_FORMAT = "HHmmss";
    public static final String LONG_DATE_TM_PART_FORMAT = "HH:mm:ss";

    /**
     *
     */
    public static final String Long_DATE_TM_PART_GBK_FORMAT = "HH时mm分ss秒";
    public static final String MAIL_DATA_DTM_PART_FORMAT = "MM月dd日HH:mm";
    public static final String POINT_DATA_DTM_PART_FORMAT = "yyyy.MM.dd";
    public static final String DEFAULT_DATE_FORMAT = US_LOCALE_DATE_FORMAT;
    public static final String DASH = "-";
    public static final String COLON = ":";
    public static long NANO_ONE_SECOND = 1000;
    public static long NANO_ONE_MINUTE = 60 * NANO_ONE_SECOND;
    public static long NANO_ONE_HOUR = 60 * NANO_ONE_MINUTE;
    public static long NANO_ONE_DAY = 24 * NANO_ONE_HOUR;

    private DateUtils() {
    }

    // ============================2.String2Date=====================================

    public static void main(String[] args) {
        String str = "20140313";
        try {
            System.out.println(DateUtils.getDaysInMonth(getNow()));
            System.out.println(getCurrentDateMinute());
            System.out.println(parseMailDateDtPartString(str));
            System.out.println(getCurrentYyMmDdTime());
            System.out.println(toMailDateString(DateUtils.addDays(DateUtils.getNow(), 0)));
            System.err.println(DateUtils.parseMailDateDtPartString("201604070"));
            System.out.println(parser("201601011200000000000", MAIL_DATE_FORMAT));
            System.out.println(getStartOfMonth(addMonths(new Date(), -5)));
            System.out.println(getStartOfMonth(addMonths(new Date(), 1)));
        } catch (ParseException e) {
            System.out.println(e.toString());
        }
    }

    /**
     * 获取当前日期 ，格式类型yyyyMMdd
     */
    public static String getCurrentDate() {
        return toMailDateDtPartString(getNow());
    }

    /**
     * 获取当前日期 ，格式类型yyyyMMddHH
     */
    public static String getCurrentDateHour() {
        return toMailDateHourDtPartString(getNow());
    }

    /**
     * 获取当前日期 ，格式类型yyyyMMddHHmm
     */
    public static String getCurrentDateMinute() {
        return toMailDateMinuteDtPartString(getNow());
    }

    /**
     * 获取当期时间，类型HHmmss
     *
     * @return
     */
    public static String getCurrentTime() {
        return toMailTimeTmPartString(getNow());
    }

    /**
     * 获取当期时间MM月dd日HH:mm
     *
     * @return
     */
    public static String getCurrentMmDdHmTime() {
        return toMailDtmPart(getNow());
    }

    /**
     * 获取当前日期和时间，格式yyyyMMddHHmmss
     *
     * @return
     */
    public static String getCurrentDateTime() {
        return toMailDateString(getNow());
    }

    /**
     * 获取当前日期类型时间
     */
    public static Date getNow() {
        String todaystr = ConfigService.getConfig("share.lp").getProperty("today_yyyyMMdd", null);
        if (StringUtils.isNotBlank(todaystr)) {
            try {
                Calendar apolloCal = Calendar.getInstance();
                Date apolloToday = new SimpleDateFormat("yyyyMMdd").parse(todaystr);
                apolloCal.setTime(apolloToday);

                Calendar cal = Calendar.getInstance();
                cal.set(Calendar.YEAR, apolloCal.get(Calendar.YEAR));
                cal.set(Calendar.MONTH, apolloCal.get(Calendar.MONTH));
                cal.set(Calendar.DAY_OF_MONTH, apolloCal.get(Calendar.DAY_OF_MONTH));

                return cal.getTime();
            } catch (ParseException e) {
                throw new BizException(BaseResultCodeEnum.FAIL.getCode(), "apollo today config parse failed", e);
            }
        }
        return new Date();
    }

    /**
     * 获取当前时间戳
     */
    public static long getNowTimestamp() {
        return getNow().getTime();
    }

    /**
     * 获取当前日期，格式yyMMdd
     */
    public static String getCurrentYyMmDdTime() {
        return toMailDateYearPartString(getNow());
    }

    // ============================3.String2String=====================================

    /**
     * 将一个日期型转换为指定格式字串
     *
     * @param aDate
     * @param formatStr
     * @return
     */
    public static final String toFormatDateString(Date aDate, String formatStr) {
        if (aDate == null)
            return StringUtils.EMPTY;
        Assert.hasText(formatStr);
        return new SimpleDateFormat(formatStr).format(aDate);

    }

    /**
     * 将一个日期型转换为'yyyy-MM-dd'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toShortDateString(Date aDate) {
        return toFormatDateString(aDate, SHORT_DATE_FORMAT);
    }
    
    /**
     * 将一个日期型转换为'yyyy/MM/dd'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toShortDateString2(Date aDate) {
        return toFormatDateString(aDate, SHORT_DATE_FORMAT2);
    }

    /**
     * 将一个日期型转换为'yyyyMMdd'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailDateDtPartString(Date aDate) {
        return toFormatDateString(aDate, MAIL_DATE_DT_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyMMdd'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailDateYearPartString(Date aDate) {
        return toFormatDateString(aDate, MAIL_DATE_YEAR_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyyMMddHH'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailDateHourDtPartString(Date aDate) {
        return toFormatDateString(aDate, MAIL_DATE_HOUR_DT_PART_FORMAT);
    }

    // ============================4.时间加减=====================================

    /**
     * 将一个日期型转换为'yyyyMMddHHmm'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailDateMinuteDtPartString(Date aDate) {
        return toFormatDateString(aDate, MAIL_DATE_MINUTE_DT_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为'HHmmss'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailTimeTmPartString(Date aDate) {
        return toFormatDateString(aDate, MAIL_TIME_TM_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyyMMddHHmmss'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailDateString(Date aDate) {
        return toFormatDateString(aDate, MAIL_DATE_FORMAT);
    }

    /**
     * 将一个日期型转换为MM月dd日HH:mm格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toMailDtmPart(Date aDate) {
        return toFormatDateString(aDate, MAIL_DATA_DTM_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为yyyy.MM.dd格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toPointDtmPart(Date aDate) {
        return toFormatDateString(aDate, POINT_DATA_DTM_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyy-MM-dd HH:mm:ss'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toLongDateString(Date aDate) {
        return toFormatDateString(aDate, LONG_DATE_FORMAT);
    }

    /**
     * 将一个日期型转换为'HH:mm:ss'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toLongDateTmPartString(Date aDate) {
        return toFormatDateString(aDate, LONG_DATE_TM_PART_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyy年MM月dd日'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toShortDateGBKString(Date aDate) {
        return toFormatDateString(aDate, SHORT_DATE_GBK_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyy年MM月dd日 HH时mm分'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toDateGBKString(Date aDate) {
        return toFormatDateString(aDate, DATE_GBK_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyy年MM月dd日 HH时mm分ss秒'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toLongDateGBKString(Date aDate) {
        return toFormatDateString(aDate, LONG_DATE_GBK_FORMAT);
    }

    /**
     * 将一个日期型转换为'HH时mm分ss秒'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toLongDateTmPartGBKString(Date aDate) {
        return toFormatDateString(aDate, Long_DATE_TM_PART_GBK_FORMAT);
    }

    // ======================================5.时间国际化=================================

    /**
     * 将一个日期型转换为'yyyy-MM-dd HH:mm:ss:SSS'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toFullDateString(Date aDate) {
        return toFormatDateString(aDate, FULL_DATE_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyy年MM月dd日 HH时mm分ss秒SSS毫秒'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toFullDateGBKString(Date aDate) {
        return toFormatDateString(aDate, FULL_DATE_GBK_FORMAT);
    }

    /**
     * 将一个日期型转换为'yyyyMMddHHmmssSSS'格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toFullDateCompactString(Date aDate) {
        return toFormatDateString(aDate, FULL_DATE_COMPACT_FORMAT);
    }

    /**
     * 将一个日期型转换为LDAP格式字串
     *
     * @param aDate
     * @return
     */
    public static final String toLDAPDateString(Date aDate) {
        return toFormatDateString(aDate, LDAP_DATE_FORMAT);
    }

    /**
     * 将一个符合指定格式的字串解析成日期型
     *
     * @param aDateStr
     * @param formatter
     * @return
     * @throws ParseException
     */
    public static final Date parser(String aDateStr, String formatter) throws ParseException {
        if (StringUtils.isBlank(aDateStr))
            return null;
        Assert.hasText(formatter);
        SimpleDateFormat sdf = new SimpleDateFormat(formatter);
        // 严格验证日期
        sdf.setLenient(false);
        return sdf.parse(aDateStr);
    }

    /**
     * 将一个符合'yyyy-MM-dd HH:mm:ss'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseLongDateString(String aDateStr) throws ParseException {
        return parser(aDateStr, LONG_DATE_FORMAT);

    }

    // ==================================6.
    // miscellaneous==========================

    /**
     * 将一个符合'yyyy-MM-dd HH:mm:ss'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseLongDateDtPartString(String aDateStr) throws ParseException {
        return parser(aDateStr, LONG_DATE_FORMAT);

    }

    /**
     * 将一个符合'yyyy-MM-dd HH:mm:ss'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseLongDateTmPartString(String aDateStr) throws ParseException {
        return parser(aDateStr, LONG_DATE_FORMAT);

    }

    /**
     * 将一个符合'yyyy-MM-dd'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseShortDateString(String aDateStr) {
        try {
            return parser(aDateStr, SHORT_DATE_FORMAT);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 将一个符合'yyyyMMddHHmmss'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseMailDateString(String aDateStr) throws ParseException {
        return parser(aDateStr, MAIL_DATE_FORMAT);

    }

	/* ------- start ------------ */

    /**
     * 将一个符合'yyyyMMdd'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseMailDateDtPartString(String aDateStr) throws ParseException {
        return parser(aDateStr, MAIL_DATE_DT_PART_FORMAT);
    }

    /**
     * 将一个符合'HHmmss'格式的字串解析成日期型
     *
     * @param aDateStr
     * @return
     */
    public static final Date parseMailDateTmPartString(String aDateStr) throws ParseException {
        return parser(aDateStr, MAIL_TIME_TM_PART_FORMAT);
    }

    /**
     * 将一个符合'yyyy-MM-dd HH:mm:ss:SSS'格式的字串解析成日期型
     *
     * @return
     */
    public static final Date parseFullDateString(String aDateStr) throws ParseException {
        return parser(aDateStr, FULL_DATE_FORMAT);

    }

    /**
     * 将一个符合'yyyyMMdd'格式的字串解析成日期型
     *
     * @return
     */
    public static final Date parseYMDDateString(String aDateStr){
        Date resp = null;
        try {
            resp = parser(aDateStr, MAIL_DATE_DT_PART_FORMAT);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return resp;
    }

    /**
     * 将一个符合'yyyy-MM-dd'、'yyyy-MM-dd HH:mm:ss'或'EEE MMM dd HH:mm:ss zzz
     * yyyy'格式的字串解析成日期型， 如果为blank则返回空，如果不为blank又不符合格式则报错
     *
     * @param aDateStr
     * @return
     */
    public static Date parseDateString(String aDateStr) {
        Date ret = null;
        if (StringUtils.isNotBlank(aDateStr)) {
            try {
                if (DateUtils.isShortDateStr(aDateStr)) {
                    ret = DateUtils.parseShortDateString(aDateStr);
                } else if (DateUtils.isLongDateStr(aDateStr)) {
                    ret = DateUtils.parseLongDateString(aDateStr);
                } else if (DateUtils.isDateStrMatched(aDateStr, DateUtils.DEFAULT_DATE_FORMAT)) {
                    ret = DateUtils.parser(aDateStr, DateUtils.DEFAULT_DATE_FORMAT);
                } else {
                    throw new IllegalArgumentException("date format mismatch");
                }
            } catch (ParseException e) {
                // 不可能到这里
            }
        }
        return ret;
    }

    /**
     * 转换日期格式 yyyy-MM-dd => yyyyMMdd
     *
     * @param dt yyyy-MM-dd
     * @return yyyyMMdd
     */
    public static String transfer2ShortDate(String dt) {
        if (dt == null || dt.length() != 10) {
            return dt;
        }
        Assert.notNull(dt);
        String[] tmp = StringUtils.split(dt, DASH);
        Assert.isTrue(tmp != null && tmp.length == 3);
        return tmp[0].concat(StringUtils.leftPad(tmp[1], 2, "0")).concat(StringUtils.leftPad(tmp[2], 2, "0"));
    }

	/* ------- end ------------ */

    /**
     * 转换日期格式 yyyyMMdd => yyyy-MM-dd
     *
     * @param dt yyyyMMdd
     * @return yyyy-MM-dd
     */
    public static String transfer2LongDateDtPart(String dt) {
        if (dt == null || dt.length() != 8) {
            return dt;
        }
        Assert.notNull(dt);
        Assert.isTrue(dt.length() == 8);
        return dt.substring(0, 4).concat(DASH).concat(dt.substring(4, 6)).concat(DASH).concat(dt.substring(6));
    }

    /**
     * 转换日期格式 HHmmss => HH:mm:ss
     *
     * @param tm HHmmss
     * @return HH:mm:ss
     */
    public static String transfer2LongDateTmPart(String tm) {
        if (tm == null || tm.length() != 6) {
            return tm;
        }
        Assert.notNull(tm);
        Assert.isTrue(tm.length() == 6);
        return tm.substring(0, 2).concat(COLON).concat(tm.substring(2, 4)).concat(COLON).concat(tm.substring(4));
    }

    /**
     * 转换日期格式 yyyyMMdd => yyyy年MM月dd日
     *
     * @param dt yyyyMMdd
     * @return yyyy年MM月dd日
     */
    public static String transfer2LongDateGbkDtPart(String dt) {
        if (dt == null || dt.length() != 8) {
            return dt;
        }
        Assert.notNull(dt);
        Assert.isTrue(dt.length() == 8);
        return dt.substring(0, 4).concat("年").concat(dt.substring(4, 6)).concat("月").concat(dt.substring(6)).concat("日");
    }

    /**
     * 转换日期格式HHmmss => HH时mm分ss秒
     *
     * @param tm HHmmss
     * @return HH时mm分ss秒
     */
    public static String transfer2LongDateGbkTmPart(String tm) {
        if (tm == null || tm.length() != 6) {
            return tm;
        }
        Assert.notNull(tm);
        Assert.isTrue(tm.length() == 6);
        return tm.substring(0, 2).concat("时").concat(tm.substring(2, 4)).concat("分").concat(tm.substring(4)).concat("秒");
    }

    /**
     * 为一个日期加上指定年数
     *
     * @param aDate
     * @param amount 年数
     * @return
     */
    public static final Date addYears(Date aDate, int amount) {
        return addTime(aDate, Calendar.YEAR, amount);
    }

    /**
     * 为一个日期加上指定月数
     *
     * @param aDate
     * @param amount 月数
     * @return
     */
    public static final Date addMonths(Date aDate, int amount) {
        return addTime(aDate, Calendar.MONTH, amount);
    }

    public static final Date copyDate(Date aDate) {
        Date date = getNow();
        date.setTime(aDate.getTime());
        return date;
    }


    /**
     * 为一个日期加上指定天数
     *
     * @param aDate
     * @param amount 天数
     * @return
     */
    public static final Date addDays(Date aDate, int amount) {
        return addTime(aDate, Calendar.DAY_OF_YEAR, amount);
    }

    public static String getCurrentDate(int year, int month, int day, int beDay) {
        GregorianCalendar newCal = new GregorianCalendar(year, month, day);
        long milSec = newCal.getTimeInMillis() - (long) beDay * 24 * 3600 * 1000;
        GregorianCalendar other = new GregorianCalendar();
        other.setTimeInMillis(milSec);
        String newYear = String.valueOf(other.get(GregorianCalendar.YEAR));
        String newMonth = String.valueOf(other.get(GregorianCalendar.MONTH) + 1);
        newMonth = newMonth.length() == 1 ? "0" + newMonth : newMonth;
        String newDay = String.valueOf(other.get(GregorianCalendar.DAY_OF_MONTH));
        newDay = newDay.length() == 1 ? "0" + newDay : newDay;
        String date = newYear + "-" + newMonth + "-" + newDay;
        return date;
    }

    /**
     * 为一个日期减去一个指定天数
     *
     * @param amount 天数
     * @return yyyy-mm-dd
     */
    public static final String minusDays(int amount) {
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR);
        int moths = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DAY_OF_MONTH);
        return getCurrentDate(year, moths, day, amount - 1);
    }

    /**
     * 为一个日期减去一个指定天数
     *
     * @param amount 天数
     * @param date   日期
     * @return yyyy-MM-dd
     */
    public static final String minusDays(String date, int amount) {
        if (date == null || date.length() != 8) {
            return date;
        }
        try {
            Calendar cal = Calendar.getInstance();
            cal.set(Integer.parseInt(date.substring(0, 4)), Integer.parseInt(date.substring(4, 6)) - 1, Integer.parseInt(date.substring(6)));
            int moths = cal.get(Calendar.MONTH);
            int day = cal.get(Calendar.DAY_OF_MONTH);
            int year = cal.get(Calendar.YEAR);
            return getCurrentDate(year, moths, day, amount);
        } catch (Exception e) {
            return null;
        }

    }

    public static Date setDay(Date time, int day) {
        if (null == time) {
            return time;
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(time);
        cal.set(Calendar.DAY_OF_MONTH, day);
        return cal.getTime();
    }



    /**
     * 为一个日期加上指定天数
     *
     * @param aDate  yyyyMMdd格式字串
     * @param amount 天数
     * @return
     */
    public static final String addDays(String aDate, int amount) {
        try {
            return DateUtils.toMailDateDtPartString(addTime(DateUtils.parseMailDateDtPartString(aDate), Calendar.DAY_OF_YEAR, amount));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 为一个日期加上指定小时数
     *
     * @param aDate
     * @param amount 小时数
     * @return
     */
    public static final Date addHours(Date aDate, int amount) {
        return addTime(aDate, Calendar.HOUR, amount);

    }

    /**
     * 为一个日期加上指定分钟数
     *
     * @param aDate
     * @param amount 分钟数
     * @return
     */
    public static final Date addMinutes(Date aDate, int amount) {
        return addTime(aDate, Calendar.MINUTE, amount);
    }

    /**
     * 为一个日期加上指定秒数
     *
     * @param aDate
     * @param amount 秒数
     * @return
     */
    public static final Date addSeconds(Date aDate, int amount) {
        return addTime(aDate, Calendar.SECOND, amount);

    }

    private static final Date addTime(Date aDate, int timeType, int amount) {
        if (aDate == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(aDate);
        cal.add(timeType, amount);
        return cal.getTime();
    }

    /**
     * 得到当前时间的UTC时间
     *
     * @return
     */
    public static final String getUTCTime() {
        return getSpecifiedZoneTime(Calendar.getInstance().getTime(), TimeZone.getTimeZone("GMT+0"));
    }

    /**
     * 得到指定时间的UTC时间
     *
     * @param aDate 时间戳
     * @return yyyy-MM-dd HH:mm:ss 格式
     */
    public static final String getUTCTime(Date aDate) {
        return getSpecifiedZoneTime(aDate, TimeZone.getTimeZone("GMT+0"));
    }

    /**
     * 得到当前时间的指定时区的时间
     *
     * @param tz
     * @return
     */
    public static final String getSpecifiedZoneTime(TimeZone tz) {
        return getSpecifiedZoneTime(Calendar.getInstance().getTime(), tz);

    }

    /**
     * 得到指定时间的指定时区的时间
     *
     * @param aDate 时间戳,Date是一个瞬间的long型距离历年的位移偏量，
     *              在不同的指定的Locale/TimeZone的jvm中，它toString成不同的显示值，
     *              所以没有必要为它再指定一个TimeZone变量表示获取它时的jvm的TimeZone
     * @param tz    要转换成timezone
     * @return yyyy-MM-dd HH:mm:ss 格式
     */
    public static final String getSpecifiedZoneTime(Date aDate, TimeZone tz) {
        if (aDate == null)
            return StringUtils.EMPTY;
        Assert.notNull(tz);
        SimpleDateFormat sdf = new SimpleDateFormat(LONG_DATE_FORMAT);
        sdf.setTimeZone(tz);
        return sdf.format(aDate);
    }

    /*************************************************************
     * function: add bar to a date string , such as if the date string is
     * "20060912090807" , the return string is "2006-09-12 09:08:07" input :
     * date string as "20060912090807" output : date string as
     * "2006-09-12 09:08:07" note : scottie xu
     *********************************************************/
    public static String addBarAndColonToDateString(String dateStr) {
        String retDateStr = "";

        if (dateStr == null || dateStr.length() != 14) {
            return dateStr;
        }

        retDateStr =
                dateStr.substring(0, 4) + "-" + dateStr.substring(4, 6) + "-" + dateStr.substring(6, 8) + " " + dateStr.substring(8, 10) + ":" + dateStr.substring(10, 12) + ":"
                        + dateStr.substring(12);

        return retDateStr;

    }

    /*************************************************************
     * function: remove the bar from a date string , such as if the date string
     * is "2006-09-12" , the return string is "20060912" . input : date string
     * as "2006-09-12" output : date string as "20060912" note : scottie xu
     *********************************************************/
    public static String removeBarFromDateString(String dateStr) {
        String retDateStr = "";

        if (dateStr == null || dateStr.length() != 10) {
            return dateStr;
        }

        retDateStr = dateStr.substring(0, 4) + dateStr.substring(5, 7) + dateStr.substring(8);

        return retDateStr;

    }

    /**
     * 计算两个日期之间相差的月数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final int getDifferenceMonths(Date startDate, Date endDate) {
        Assert.notNull(startDate);
        Assert.notNull(endDate);
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

        return Math.abs((startCal.get(Calendar.YEAR) - endCal.get(Calendar.YEAR)) * 12 + (startCal.get(Calendar.MONTH) - endCal.get(Calendar.MONTH)));
    }
    
    /**
     * 计算两个日期之间相差的月数-自然月
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final int getBetweenMonths(Date startDate, Date endDate) {
        Assert.notNull(startDate);
        Assert.notNull(endDate);
        DateTime start = new DateTime(startDate);
        DateTime end = new DateTime(endDate);
        return Months.monthsBetween(start, end).getMonths();
    }

    /**
     * 计算两个日期之间相差的月数
     *
     * @param startDateStr yyyy-mm-dd
     * @param endDateStr   yyyy-mm-dd
     * @return
     */
    public static final int getDifferenceMonths(String startDateStr, String endDateStr) {
        DateUtils.checkShortDateStr(startDateStr);
        DateUtils.checkShortDateStr(endDateStr);
        try {
            return getDifferenceMonths(parseShortDateString(startDateStr), parseShortDateString(endDateStr));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param startDateStr yyyy-mm-dd
     * @param endDateStr   yyyy-mm-dd
     * @return
     */
    public static final int getDifferenceDays(String startDateStr, String endDateStr) {
        return new Long(getDifferenceMillis(startDateStr, endDateStr) / (NANO_ONE_DAY)).intValue();
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param startDateStr yyyymmdd
     * @param endDateStr   yyyymmdd
     * @return
     */
    public static final int getDifferenceDays2(String startDateStr, String endDateStr) {
        return new Long(getDifferenceMillis(startDateStr, endDateStr, MAIL_DATE_DT_PART_FORMAT) / (NANO_ONE_DAY)).intValue();
    }

    /**
     * 两个日期之间相减（存在负数）
     *
     * @param startDateStr yyyy-mm-dd
     * @param endDateStr   yyyy-mm-dd
     * @return
     */
    public static final int getDaysSubtract(String startDateStr, String endDateStr) {
        return new Long(getDaysSubtractMillis(startDateStr, endDateStr) / (NANO_ONE_DAY)).intValue();
    }

    /**
     * 两个日期之间相减（存在负数）
     *
     * @param startDateStr yyyymmdd
     * @param endDateStr   yyyymmdd
     * @return
     */
    public static final int getDaysSubtract2(String startDateStr, String endDateStr) {
        return new Long(getDaysSubtractMillis(startDateStr, endDateStr, MAIL_DATE_DT_PART_FORMAT) / (NANO_ONE_DAY)).intValue();
    }

    /**
     * 两个日期之间相减（存在负数）
     *
     * @param startDateStr yyyy-mm-dd
     * @param endDateStr   yyyy-mm-dd
     * @return
     * @throws ParseException
     */
    public static final long getDaysSubtractMillis(String startDateStr, String endDateStr) {
        return getDaysSubtractMillis(startDateStr, endDateStr, SHORT_DATE_FORMAT);
    }

    /**
     * 计算两个日期之间相差的的毫秒数（存在负数）
     *
     * @param startDateStr
     * @param endDateStr
     * @param dateFormat
     * @return
     */
    public static final long getDaysSubtractMillis(String startDateStr, String endDateStr, String dateFormat) {
        try {
            return getDaysSubtractMillis(parser(startDateStr, dateFormat), parser(endDateStr, dateFormat));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算两个日期之间相差的的毫秒数（存在负数）
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final long getDaysSubtractMillis(Date startDate, Date endDate) {
        Assert.notNull(startDate);
        Assert.notNull(endDate);
        return endDate.getTime() - startDate.getTime();
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final int getDifferenceDays(Date startDate, Date endDate) {
        return new Long(getDifferenceMillis(startDate, endDate) / (NANO_ONE_DAY)).intValue();
    }
    
    /**
     * 计算两个日期之间相差的天数,后面减前面,不用取绝对值
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final int getSubtractDays(Date startDate, Date endDate) {
        return new Long(getSubtractMillis(startDate, endDate) / (NANO_ONE_DAY)).intValue();
    }

    /*************************************************************
     * function: delete the space input : string as "  2  " output : string as
     * "2" note : richard zhang
     *********************************************************/
    public static String deleteLRSpace(String a) {
        int i, j;
        int m = 0, n = 0;
        int len = a.length();
        String c = "";
        for (i = 0; i < len; i++) {
            if (a.substring(i, i + 1).equals("　") || a.substring(i, i + 1).equals(" ")) {
                m++;
            } else {
                break;
            }
        }
        if (m < len) {
            for (j = len - 1; j > 0; j--) {
                if (a.substring(j, j + 1).equals("　") || a.substring(j, j + 1).equals(" ")) {
                    n++;
                } else {
                    break;
                }
            }
            c = a.substring(m, len - n);
        }
        return (c);
    }

    /**
     * 计算两个日期之间相差的的毫秒数
     *
     * @param startDateStr yyyy-mm-dd
     * @param endDateStr   yyyy-mm-dd
     * @return
     * @throws ParseException
     */
    public static final long getDifferenceMillis(String startDateStr, String endDateStr) {
        return getDifferenceMillis(startDateStr, endDateStr, SHORT_DATE_FORMAT);
    }

    /**
     * 计算两个日期之间相差的的毫秒数
     *
     * @param startDateStr yyyyMMddHHmmss
     * @param endDateStr   yyyyMMddHHmmss
     * @return
     * @throws ParseException
     */
    public static final long getDifferenceMillis2(String startDateStr, String endDateStr) {
        return getDifferenceMillis(startDateStr, endDateStr, MAIL_DATE_FORMAT);
    }

    /**
     * 计算两个日期之间相差的的毫秒数
     *
     * @param startDateStr
     * @param endDateStr
     * @param dateFormat
     * @return
     */
    public static final long getDifferenceMillis(String startDateStr, String endDateStr, String dateFormat) {
        try {
            return getDifferenceMillis(parser(startDateStr, dateFormat), parser(endDateStr, dateFormat));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算两个日期之间相差的的毫秒数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final long getDifferenceMillis(Date startDate, Date endDate) {
        Assert.notNull(startDate);
        Assert.notNull(endDate);
        return Math.abs(endDate.getTime() - startDate.getTime());
    }
    
    /**
     * 计算两个日期之间相差的的毫秒数,后面减前面,不用取绝对值
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static final long getSubtractMillis(Date startDate, Date endDate) {
        Assert.notNull(startDate);
        Assert.notNull(endDate);
        return endDate.getTime() - startDate.getTime();
    }

    /**
     * 检验 日期是否在指定区间内，如果格式错误，返回false
     * 如果maxDateStr或minDateStr为空则比较时变为正负无穷大，如果都为空，则返回false
     *
     * @param aDate
     * @param minDateStr 必须是yyyy-MM-dd格式，时分秒为00:00:00
     * @param maxDateStr 必须是yyyy-MM-dd格式，时分秒为00:00:00
     * @return
     */
    public static final boolean isDateBetween(Date aDate, String minDateStr, String maxDateStr) {
        Assert.notNull(aDate);
        boolean ret = false;
        try {
            Date dMaxDate = null;
            Date dMinDate = null;
            dMaxDate = DateUtils.parseShortDateString(maxDateStr);
            dMinDate = DateUtils.parseShortDateString(minDateStr);
            switch ((dMaxDate != null ? 5 : 3) + (dMinDate != null ? 1 : 0)) {
                case 6:
                    ret = aDate.before(dMaxDate) && aDate.after(dMinDate);
                    break;
                case 5:
                    ret = aDate.before(dMaxDate);
                    break;
                case 4:
                    ret = aDate.after(dMinDate);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return ret;
    }

    /**
     * 计算某日期所在月份的天数
     *
     * @param aDateStr yyyy-mm-dd
     * @return
     */
    public static final int getDaysInMonth(String aDateStr) {
        DateUtils.checkShortDateStr(aDateStr);
        try {
            return getDaysInMonth(parseShortDateString(aDateStr));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算某日期所在月份的天数
     *
     * @param aDateStr yyyymmdd
     * @return
     */
    public static final int getMailDaysInMonth(String aDateStr) {
        DateUtils.isMailDateDtPartStr(aDateStr);
        try {
            return getDaysInMonth(parseMailDateDtPartString(aDateStr));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算某日期所在月份的总天数
     *
     * @param aDate
     * @return
     */
    public static final int getDaysInMonthAll(Date aDate) {
        Assert.notNull(aDate);
        Calendar cal = Calendar.getInstance();
        cal.setTime(aDate);
        return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    }
    
    /**
     * 计算某日期所在月份的天数
     *
     * @param aDate
     * @return
     */
    public static final int getDaysInMonth(Date aDate) {
        Assert.notNull(aDate);
        Calendar cal = Calendar.getInstance();
        cal.setTime(aDate);
        return cal.get(Calendar.DATE);
    }

    /*************************************************************
     * function: add Chinese to a date string , such as if the date string is
     * "20060912" , the return string is "2006-09-12" input : date string as
     * "20060912" output : date string as "2006-09-12" note : man wu
     *********************************************************/
    public static String toDateString(String dateStr) {
        String retDateStr = "";

        if (dateStr == null || dateStr.length() != 8) {
            return dateStr;
        }

        retDateStr = dateStr.substring(0, 4) + "-" + dateStr.substring(4, 6) + "-" + dateStr.substring(6);

        return retDateStr;

    }

    public static boolean isDate(String dateStr, String formatStr) {
        if (dateStr == null) {
            return false;
        }
        if (formatStr == null) {
            return false;
        }
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        try {
            format.parse(dateStr);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 判断字串是否符合yyyy-MM-dd格式
     *
     * @param aDateStr
     * @return
     */
    public static final boolean isShortDateStr(String aDateStr) {
        try {
            DateUtils.parseShortDateString(aDateStr);
        } catch (Exception e) {
            throw new RuntimeException(e);

            // return false;
        }
        return true;
    }

    /**
     * 判断字串是否符合yyyy-MM-dd HH:mm:ss格式
     *
     * @param aDateStr
     * @return
     */
    public static final boolean isLongDateStr(String aDateStr) {
        try {
            DateUtils.parseLongDateString(aDateStr);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    public static final boolean isMailDateStr(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return false;
        }
        try {
            DateUtils.parseMailDateString(dateStr);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 判断字串是否符合指定的日期格式
     *
     * @param aDateStr
     * @param formatter
     * @return
     */
    public static final boolean isDateStrMatched(String aDateStr, String formatter) {
        try {
            DateUtils.parser(aDateStr, formatter);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 检查字串是否符合yyyy-MM-dd格式
     *
     * @param aDateStr
     */
    public static final void checkShortDateStr(String aDateStr) {
        Assert.isTrue(isShortDateStr(aDateStr), "The str-'" + aDateStr + "' must match 'yyyy-MM-dd' format.");
    }

    /**
     * 判断字串是否符合yyyyMMdd格式
     *
     * @param aDateStr
     * @return
     */
    public static final boolean isMailDateDtPartStr(String aDateStr) {
        try {
            DateUtils.parseMailDateDtPartString(aDateStr);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 判断字串是否符合yyyyMMddhhmmss格式
     *
     * @param aDateStr
     * @return
     */
    public static final boolean isDateDtPartStr(String aDateStr) {
        try {
            DateUtils.parseMailDateString(aDateStr);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 检验输入是否为正确的日期格式(不含秒的任何情况),严格要求日期正确性,格式:yyyyMMdd
     *
     * @param sourceDate
     * @return
     */
    public static boolean isMailDateDtFormat(String sourceDate, String dtFormat) {
        if (StringUtils.isBlank(sourceDate)) {
            return false;
        }
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(dtFormat);
            dateFormat.setLenient(false);
            dateFormat.parse(sourceDate);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获得月底最后一天的日期
     *
     * @return
     */
    public static Date getLastDayOfMonth(Date batchDate) {
        Calendar c = Calendar.getInstance();
        c.setTime(batchDate);
        c.add(Calendar.MONTH, 1);
        c.set(Calendar.DATE, 1);
        c.add(Calendar.DATE, -1);
        return c.getTime();
    }

    /**
     * 获得给定两个日期之间相隔的月数，算到日
     *
     * @param from
     * @param to
     * @return
     */
    public static int getMonthInterval(Date from, Date to) {
        Calendar f = Calendar.getInstance();
        f.setTime(from);
        Calendar t = Calendar.getInstance();
        t.setTime(to);
        int year = t.get(Calendar.YEAR) - f.get(Calendar.YEAR);
        int month = t.get(Calendar.MONTH) - f.get(Calendar.MONTH);
        return year * 12 + month;
    }

    /**
     * 日期比较
     *
     * @param date1
     * @param date2
     * @return int date1 > date2 =1；date1 = date2 =0；date1 <date2 =-1
     * @throws @since 1.0.0
     */
    public static int dateCompare(Date date1, Date date2) {
        return dateCompare(DateFormatUtils.ISO_DATE_FORMAT.format(date1), DateFormatUtils.ISO_DATE_FORMAT.format(date2));
    }

    /**
     * 日期比较
     *
     * @param date1
     * @param date2
     * @return int date1 > date2 =1；date1 = date2 =0；date1 <date2 =-1
     * @throws @since 1.0.0
     */
    public static int dateCompare(String date1, String date2) {
        int i = 0;
        SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd");
        try {
            i = sm.parse(date1).compareTo(sm.parse(date2));
        } catch (ParseException e) {
            throw new RuntimeException("日期字符串无法解析");
        }
        return i;
    }

    /**
     * 坑爹账龄计算要求，只有大于90天才算账龄4
     * @param dueDate 到期日
     * @param now     当前日期
     * @return 账龄
     * @Description 计算从到期日到当前日期的账龄
     */
    public static int getDelqAge(Date dueDate, Date now) {
        int aging = 0;
        Calendar cal = Calendar.getInstance();
        cal.setTime(dueDate);
        int day = cal.get(Calendar.DAY_OF_MONTH); // 到期日号数
        cal.setTime(now);
        cal.add(Calendar.DATE, -1); // 当前日期减去1天，因为到期日计算时算头不算尾
        int mth = cal.get(Calendar.MONTH); // 当前月数
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.add(Calendar.DATE, day - 1);
        Date after = cal.getTime(); // 到期日号数减一天
        if (cal.get(Calendar.MONTH) != mth) {
            after = getLastDayOfMonth(now);
        }
        int diff = getMonthInterval(dueDate, after) + 1;// 到期日当天的批量账龄就是1
        switch (dateCompare(after, now)) {
            case 1:
                aging = diff - 1;
                break;
            case 0:
                aging = diff;
                break;
            case -1:
                aging = diff;
                break;
            default:
                aging = diff;
                break;
        }
        int overdueDays = DateUtils.getIntervalDays(dueDate, now);
        if(overdueDays > 90){
            aging = 4;
        }else{
            if(aging == 4){
                aging = 3;
            }
        }
        return aging;
    }

    /**
     * @param dueDate 到期日
     * @param now     当前日期
     * @return 账龄
     * @Description 计算从到期日到当前日期的账龄(普通贷款，30天一个账龄单位)
     */
    public static int getDelqAgeNormal(Date dueDate, Date now) {
        int day = getSubtractDays(dueDate, now) + 1; // 逾期当天批量过后算逾期一天
        return (day / 30) + 1;
    }

    public static int calAgeByOverdueDays(Date bussDate, Date dueDate, int overdueDays) {
        Calendar bussDateCal = Calendar.getInstance();
        bussDateCal.setTime(bussDate);

        Calendar dueDateCal = Calendar.getInstance();
        dueDateCal.setTime(dueDate);
        int day = dueDateCal.get(Calendar.DAY_OF_MONTH); // 到期日号数
        if(overdueDays <= 0){
            return 0;
        }else{
            int aging = 0;
            for(int i = overdueDays; i > 0; i-- ){
                int beforeDay = bussDateCal.get(Calendar.DAY_OF_MONTH);
                if(day == beforeDay){
                    aging += 1;
                }
                bussDateCal.add(Calendar.DATE, -1); // 当前日期减去1天，因为到期日计算时算头不算尾
            }
            if(overdueDays > 90){
                aging = 4;
            }else{
                if(aging == 4){
                    aging = 3;
                }
            }
            return aging;
        }
    }

    /**
     * 13位时间戳转Date
     *
     * @param time
     * @return
     */
    public static Date timestamp13ToDate(long time) {
        long temp = time;
        Timestamp ts = new Timestamp(temp);
        Date date = getNow();
        try {
            date = ts;
        } catch (Exception e) {
            log.error("TimeExchangeUtil.timestamp13ToDate(); 发生异常", e);
        }
        return date;
    }

    /**
     * Date类型转换为13位时间戳
     *
     * @param time
     * @return
     */
    public static long dateToTimestamp13(Date time) {
        Timestamp ts = new Timestamp(time.getTime());
        return (ts.getTime());
    }

    /**
     * @param date
     * @return
     * @Description 补全日期到当日最后一秒
     */
    public static Date toLastSecond(Date date) {
        Date newDate = org.apache.commons.lang3.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH);
        newDate = addHours(newDate, 23);
        newDate = addMinutes(newDate, 59);
        newDate = addSeconds(newDate, 59);
        return newDate;
    }

    public static Date getDate(String dataStr, String format) {
        try {
            return new SimpleDateFormat(format).parse(dataStr);
        } catch (ParseException e) {
            return null;
        }
    }

    public static Date getToday() {
        DateTime jodatime = new DateTime(getNow().getTime());
        LocalDate today = jodatime.toLocalDate();

        DateTime startOfToday = today.toDateTimeAtStartOfDay();

        return startOfToday.toDate();
    }

    public static int getIntervalDays(Date earlier, Date later) {
        DateTime _later = new DateTime(later.getTime());
        DateTime _earlier = new DateTime(earlier.getTime());
        int result = Days.daysBetween(_earlier.withTimeAtStartOfDay() , _later.withTimeAtStartOfDay() ).getDays();

        return result;
    }
    
    /**
     * 获得某天最大时间 2017-10-15 23:59:59
     * @param date
     * @return
     */
    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());;
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    /**
     * java8 计算相隔天数
     * @param date1
     * @param date2
     * @return
     */
    public static int getBetweenDays(Date date1, Date date2) {
    	LocalDateTime localDateTime1 = LocalDateTime.ofInstant(Instant.ofEpochMilli(date1.getTime()), ZoneId.systemDefault());
    	java.time.LocalDate localDate1 = localDateTime1.toLocalDate();
    	LocalDateTime localDateTime2 = LocalDateTime.ofInstant(Instant.ofEpochMilli(date2.getTime()), ZoneId.systemDefault());
    	java.time.LocalDate localDate2 = localDateTime2.toLocalDate();
    	Period period = Period.between(localDate1, localDate2);
    	return Math.abs(period.getDays());
    }

    /**
     * 计算悦票剩余天数
     * @param date1
     * @param date2
     * @return
     */
    public static int getBetweenDay(Date date1, Date date2,int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);
        long time1 = calendar.getTimeInMillis();
        calendar.setTime(date2);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);
        long time2 = calendar.getTimeInMillis();
        long days = (time1-time2)/(24*60*60*1000);
        return Math.addExact(Integer.parseInt(String.valueOf(days)),day);
    }

    public static Date getStartOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);
        return calendar.getTime();
    }
}
